/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		ntds ldap lookup guid.cpp
 * PURPOSE:		NTDS over LDAP support
 *				module export class
 */

namespace Ldap
{

class NtdsLdapModule : public NtdsLdapModuleBase
{
public:
	NtdsLdapModule() :
		NtdsLdapModuleBase(&StaticLdapOpts)
	{}

	PCWSTR ModuleName() override
	{
		return L"Ntds";
	}

	virtual SDE_OPTS &ModuleOptions() override
	{
		return ModOpts;
	}

private:
	static int ExceptionToOpenStatus(EXCEPTION_POINTERS *ExceptionPointers, Module::OPEN_STATUS &OpenStatus, BOOLEAN ObjectWanted)
	{
		if(ExceptionPointers->ExceptionRecord->ExceptionCode == STATUS_WIN32_ERROR)
			switch(CodeFromExceptionRecord(ExceptionPointers->ExceptionRecord))
			{
			case ERROR_ACCESS_DENIED:
				OpenStatus |= Module::SECURITY_FAILURE;
				if(ObjectWanted)
					OpenStatus |= Module::OBJECT_OPEN_FAIL;
				break;

			case ERROR_FILE_NOT_FOUND:
			case ERROR_PATH_NOT_FOUND:
			case ERROR_INVALID_DRIVE:
			case ERROR_NOT_FOUND:
				if(ObjectWanted)
					OpenStatus |= Module::OBJECT_NAME_NOTFOUND;
				break;

			case ERROR_INVALID_NAME:
			case ERROR_INVALID_NETNAME:
			case ERROR_INVALID_SHARENAME:
				if(ObjectWanted)
					OpenStatus |= Module::OBJECT_NAME_INVALID;
				break;

			default:
				if(ObjectWanted)
					OpenStatus |= Module::OBJECT_OPEN_FAIL;
				break;
			}

		OpenStatus |= Module::COMPLETE_FAILURE;

		return EXCEPTION_CONTINUE_SEARCH; //just passing through
	}

	void OpenResourcesGuarded(Module::OPEN_STATUS &OpenStatus, SDE_GENERIC_OPTS const &GOpts, Module::ModuleResourceDest &Res, UCHAR Privileges, BOOLEAN ObjectWanted)
	{
		PCWSTR Type = GOpts.ObjType;
		PCWSTR Name = GOpts.ObjName;
		auto_refct<LdapConnection> Lc;

		if(ObjectWanted)
		{
			if(Type && _wcsicmp(Type, L"Ntds") == 0)
			{
				if(!Name)
				{
					OpenStatus |= Module::OBJECT_NAME_INVALID | Module::COMPLETE_FAILURE;
					RaiseTextError(L"Name of NTDS object required, e.g. CN=Users,DC=example,DC=com");
				}

				auto_refct<LdapConnection> Lc = new LdapConnection(this, GOpts, Privileges, Name);

				Res.Object(new NtdsObject(Lc, Name));
			}
			else
			{
				OpenStatus |= Module::OBJECT_UNKNOWN_TYPE;
				Lc = LdapConnection::TryOpenConnection(this, GOpts);
			}
		}
		else
			Lc = LdapConnection::TryOpenConnection(this, GOpts);

		if(Lc)
		{
			auto_refct<ObjTypeGuidEnumerator> ObjTypeEnum = new ObjTypeGuidEnumerator(Lc);
			Res.GuidTypeEnumerator(L"Ntds", ObjTypeEnum);

			auto_refct<ObjInhTypeGuidEnumerator> ObjInhTypeEnum = new ObjInhTypeGuidEnumerator(Lc);
			Res.GuidInhTypeEnumerator(L"Ntds", ObjInhTypeEnum);

			auto_refct<GuidTypeTranslator> ObjTypeTrans = new GuidTypeTranslator(Lc);
			Res.GuidTypeTranslator(L"Ntds", ObjTypeTrans);

			auto_refct<GuidInhTypeTranslator> ObjInhTypeTrans = new GuidInhTypeTranslator(Lc);
			Res.GuidInhTypeTranslator(L"Ntds", ObjInhTypeTrans);

			auto_refct<SidTranslator> SidTrans = new SidTranslator(Lc);
			Res.SidTranslator(L"Ntds", SidTrans);

			auto_refct<DomainAccountEnumerator> SidEnum = new DomainAccountEnumerator(this);
			Res.DomainSidEnumerator(SidEnum);
		}
		else
		{
			OpenStatus |= Module::MODULE_IRRELEVANT | Module::COMPLETE_FAILURE;
		}
	}

public:
	virtual void OpenResources(Module::OPEN_STATUS &OpenStatus, SDE_GENERIC_OPTS const &GOpts, Module::ModuleResourceDest &Res, UCHAR Privileges, BOOLEAN ObjectWanted) override
	{
		__try
		{
			OpenResourcesGuarded(OpenStatus, GOpts, Res, Privileges, ObjectWanted);
		}
		__except(ExceptionToOpenStatus(exception_info(), OpenStatus, ObjectWanted))
		{}
	}
};

}//namespace Ldap